package com.amazon.line.parser;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Salman Noor, Shcool of Electrical and Information Engineering
 * @Copyright: Wits University 2013 - All Rights Reserved @email
 * salmannoor74415@gmail.com @License BSD License
 * (http://www.linfo.org/bsdlicense.html)
 */
public class CommandParser {

    private String theLine = "";
    private String operation = "";
    private int lineNumber;
    private Class OperationClassToInstatiate;
    private List<Integer> parameters = new ArrayList();

    public CommandParser(String theLine, int lineNumber) {
        this.theLine = theLine;
        this.lineNumber = lineNumber;
    }

    public void ParseAndExecuteLine() {
        theLine = theLine.replaceAll("\\s", "");

        if (theLine.matches("^[A-Za-z0-9,:-]+$")) {
            String[] commandParameterTokens = theLine.split(":");
            if (commandParameterTokensValid(commandParameterTokens)) {
                if (this.operationExists(commandParameterTokens[0].toLowerCase()) && this.parmetersValid(commandParameterTokens[1])) {
                    this.executeCommand();
                }
            }

        } else {
            System.err.println("The command line '" + theLine + "' on line '" + lineNumber + "' within the text file is invalid.");
        }

    }

    private boolean operationExists(String operation) {
        try {
            this.OperationClassToInstatiate = Class.forName("com.amazon.operations." + operation);
            this.operation = operation.toUpperCase();
        } catch (ClassNotFoundException Exception) {
            System.err.println("The command line '" + theLine + "' on line '" + lineNumber + "' within the text file is invalid. Command '" + operation + "' does not exist.");

            return false;
        }

        return true;
    }

    private boolean parmetersValid(String theParameters) {
        String[] strParameterArr = theParameters.split(",");
        for (String p : strParameterArr) {
            try {
                if (Integer.parseInt(p) < 0) {
                    System.err.println("The command line '" + theLine + "' on line '" + lineNumber + "' within the text file is invalid. The parameter '" + p + "' is negative. Only positive numbers are allowed.");
                    return false;
                }
                this.parameters.add(Integer.parseInt(p));
            } catch (NumberFormatException ex) {
                System.err.println("The command line '" + theLine + "' on line '" + lineNumber + "' within the text file is invalid. The parameter '" + p + "' is invalid.");

                return false;
            }



        }
        return true;

    }

    private boolean commandParameterTokensValid(String[] commandParameterTokens) {
        if (commandParameterTokens.length != 2) {
            System.err.println("The command line '" + theLine + "' on line '" + lineNumber + "' within the text file is invalid. Expecting one colon with a command and parameters on either side.");
            return false;
        }
        return true;
    }
    
    
    private void executeCommand(){
        Method findResultMethod;
        Method setParametersMethod;
        try {
            findResultMethod = this.OperationClassToInstatiate.getMethod("findResult");
            setParametersMethod = this.OperationClassToInstatiate.getMethod("setParameters",ArrayList.class);
             Object instantiatedOperationsClass = this.OperationClassToInstatiate.newInstance();
             setParametersMethod.invoke(instantiatedOperationsClass, this.parameters);
             Integer result = (Integer) findResultMethod.invoke(instantiatedOperationsClass);
             System.out.println(this.operation+": "+result);
               
        } catch (InvocationTargetException ex) {
            Logger.getLogger(CommandParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(CommandParser.class.getName()).log(Level.SEVERE, null, ex);
        }         
        catch (NoSuchMethodException ex) {
            Logger.getLogger(CommandParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException ex) {
            Logger.getLogger(CommandParser.class.getName()).log(Level.SEVERE, null, ex);
        }         
        catch (InstantiationException ex) {
            Logger.getLogger(CommandParser.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(CommandParser.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
